﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EngineLayer.Model
{
    using DBLayer;
    using EngineLayer.Common;
    using System.ComponentModel;
  
     partial class Library
        {
            internal Products products;
        
            public Products Products
            {
                get {
                    if (products == null)
                        products = new Products(this.application);
                
                         return this.products; 
                    }
            }

            public void products_Changed(object sender, EventArgs e)
            {
                System.Windows.Forms.MessageBox.Show("change LIbrary  " + sender.ToString());
            }
        }

    public sealed class Product : IEditable  
    {
        private GenericProperty<int> id;
        private GenericProperty<string> name;
        private GenericProperty<int> categoryID;
        private GenericProperty<string> description;
        private GenericProperty<double> price;
        private GenericProperty<bool> isPublic;
        private GenericProperty<Category> category;

        private ProductCategories categories;
        public DBLayer.Product product { get; set; }

        private ObjectStatus Status;
       
        private Entities database;
        private bool changing = false;

        # region Properties

        public int Id
        {
            get { return this.id.Value; }
            set { this.id.Value = value; }
        }
        
        public string Name
        {
            get { return this.name.Value; }
            set { this.name.Value = value; }
        }

        public string Description
        {
            get { return this.description.Value; }
            set { this.description.Value = value; }
        }

        public int CategoryID
        {
            get { return this.categoryID.Value; }
            set { this.categoryID.Value = value; }
        }

        public Category Category
        {
            get { return this.category.Value; }
            set { this.category.Value = value; }
        }
        
        public double Price
        {
            get { return this.price.Value; }
            set { this.price.Value = value; }
        }

        public bool Public
        {
            get { return this.isPublic.Value; }
            set { this.isPublic.Value = value; }
        }
        
        # endregion

        #region Events 
            
            public EventHandler IdChanged
            {
                get { return id.PropertyChanged; }
            }

        #endregion

        public Product(Entities db = null)
        {
            database = db;
            Status = (db == null ? ObjectStatus.IsNew : ObjectStatus.Original);

            id = new GenericProperty<int> ();
            name = new GenericProperty<string>();
            categoryID = new GenericProperty<int>();
            description = new GenericProperty<string>();
            price = new GenericProperty<double>();
            isPublic = new GenericProperty<bool>();
            category = new GenericProperty<Category>();

        }

        internal void property_BeforeEdit(object sender, EventArgs e)
        { 
            if (true)//readonly
            {
               //IsEditing = true;
            }
            else
                throw new Exception(Resources.ErrorMessages.AccessDenied);
        }

        public bool IsEditable()
        { 
            return changing; 
        }

        public bool IsEditing()
        {
            return false;
        }

        public bool IsNew()
        {
            return (this.Status == ObjectStatus.IsNew);
        }

        public bool IsDeleted()
        { 
         return (Status == ObjectStatus.IsDeleted);
        }
       
        internal void property_ValueChanged(object sender, EventArgs e)
        {
            Status = ObjectStatus.IsEdited;
        }

        public void BeginEdit()
        {
            this.changing = true;
        }

        public void EndEdit()
        {
            //commit    - IsEdited &&
            if (product != null && this.Status == ObjectStatus.IsEdited)
            {
                this.product.Id = this.id;
                this.product.Name = this.name;
                this.product.Description = this.description;
                this.product.ProductCategoryId = this.categoryID;
                this.product.Price = this.price;
                this.product.Public = this.isPublic;
                
                database.SaveChanges();
            }
          //  this.IsReadOnly = true;
        }

        public void CancelEdit()
        {
            //Rollback
            Status = ObjectStatus.Original;
            changing = false;
        
        }

        public void Delete()
        {
            this.Status = ObjectStatus.IsDeleted;
        }

    }

    public sealed class Products : ILibraryCollection<Product>, IEditableObject
    {
        private bool isEditable = false;
        private MyApplication app;
        private List<Product> products;

        internal Products(MyApplication application)
        {
            this.app = application;
            products  = new List<Product>();
            LoadProducts();
        }

        private void LoadProducts()
        {
            foreach (var element in app.Database.Products)
            {
                Product product = new Product(app.Database);
                product.Id = element.Id;
                product.Name = element.Name;
                product.Description = element.Description;
                product.CategoryID = element.ProductCategoryId;
                product.Price = element.Price;
                product.Public = element.Public;
                product.Category = new Category{ Id = element.ProductCategory.Id, Name = element.ProductCategory.Name, Description = element.ProductCategory.Description };
                product.product = element;

              //  product.Id.PropertyChanging += product.property_BeforeEdit;
                //product.Name.PropertyChanging += product.property_BeforeEdit;
                //product.description.PropertyChanging += product.property_BeforeEdit;
                //product.category.PropertyChanging += product.property_BeforeEdit;
                //product.price.PropertyChanging += product.property_BeforeEdit;

                //product.id.PropertyChanged += product.property_ValueChanged;
                //product.Name.PropertyChanged += product.property_ValueChanged;
                //product.description.PropertyChanged += product.property_ValueChanged;
                //product.category.PropertyChanged += product.property_ValueChanged;
                //product.price.PropertyChanged += product.property_ValueChanged;

                products.Add(product);
             }
        }
  
        public void BeginEdit()
        {
            this.isEditable = true;
        }
      
        public void EndEdit()
        {
            //commit for new
            foreach (var item in this.products.Where(item => item.IsNew() == true ))
            {
                item.BeginEdit();
                item.product = app.Database.CreateObject<DBLayer.Product>();
                item.EndEdit();
            }
            //commit doe deleted ones
            foreach (var item in this.products.Where(item => item.IsDeleted() == true))
            {
                app.Database.DeleteObject(item.product);
            }

            app.Database.SaveChanges();
            this.isEditable = false;
        }
     
        public void CancelEdit()
        {
        //rollback changes
        }

        public bool IsEditable
        {
            get { return isEditable; }
        }

        public IEnumerator<Product> GetEnumerator()
        {   
            foreach (var item in products)
            { 
                yield return item;
            }
        }
       
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    
        public int Count
        {
            get { return this.products.Count; }
        }

        public bool IsReadOnly
        {
            get { return false;}
        }

        public void Add(Product p)
        {
            if (this.isEditable)
            { 
                this.products.Add(p);
            }
            else
                throw new Exception(Resources.ErrorMessages.AccessDenied);
        }

        public void Clear()
        {
            if (this.isEditable)
                this.products.Clear();
            else
                throw new Exception(Resources.ErrorMessages.AccessDenied);
           
        }

        public bool Contains(Product p)
        {
            return this.products.Contains(p);
        }
             
        public void Delete(Product p)
        {
            this.products.Remove(p);
        }

        public Product Find(string value)
        {
            return this.products.FirstOrDefault(item => item.Name.ToUpper().Contains(value.ToUpper())); ;

        }

        public Product Find(int value)
        {
            return this.products.FirstOrDefault(item => item.Id == value);

        }

    }

   // public class InstanceHolder<TLibraryInstance>
   // {
   //     protected TLibraryInstance instance { get; set; }
   // }


   // public  class LibraryCollection<TLibraryInstance> :  InstanceHolder<TLibraryInstance>, IList<TLibraryInstance>//ILibraryItem<TLibraryInstance>
   // where TLibraryInstance : class
   //{  
   //    public void AddNew(TLibraryInstance add)
   //    {
   //        this.instance = (TLibraryInstance)Activator.CreateInstance(typeof(TLibraryInstance), true);
   //    }

   //    public void Delete(TLibraryInstance del)
   //    { 
       
   //    }

   //    public void Find(string get)
   //    { 
       
   //    }
   
   
   //}
}
